home *** CD-ROM | disk | FTP | other *** search
/ Ham Radio 2000 #2 / Ham Radio 2000 - Volume 2.iso / HAMV2 / TCP_IP / TNOS230S / TCPSUBR.C < prev    next >
C/C++ Source or Header  |  1996-12-23  |  8KB  |  372 lines

  1. /* Low level TCP routines:
  2.  *  control block management
  3.  *  sequence number logical operations
  4.  *  state transitions
  5.  *  RTT cacheing
  6.  *  garbage collection
  7.  *
  8.  * Copyright 1991 Phil Karn, KA9Q
  9.  */
  10. #include "global.h"
  11. #include "timer.h"
  12. #include "mbuf.h"
  13. #include "netuser.h"
  14. #include "internet.h"
  15. #include "tcp.h"
  16.  
  17. #if !defined(_lint)
  18. static char rcsid[] OPTIONAL = "$Id: tcpsubr.c,v 1.10 1996/12/23 20:37:36 root Exp root $";
  19. #endif
  20.  
  21. /* TCP connection states */
  22. const char *Tcpstates[] =
  23. {
  24.     "",
  25.     "Closed",
  26.     "Listen",
  27.     "SYN sent",
  28.     "SYN received",
  29.     "Established",
  30.     "FIN wait 1",
  31.     "FIN wait 2",
  32.     "Close wait",
  33.     "Last ACK",
  34.     "Closing",
  35.     "Time wait"
  36. };
  37.  
  38. /* TCP closing reasons */
  39. const char *Tcpreasons[] =
  40. {
  41.     "Normal",
  42.     "Reset/Refused",
  43.     "Timeout",
  44.     "ICMP"
  45. };
  46.  
  47. struct tcb *Tcbs;        /* Head of control block list */
  48. int16 Tcp_mss = DEF_MSS;    /* Maximum segment size to be sent with SYN */
  49. int32 Tcp_irtt = DEF_RTT;    /* Initial guess at round trip time */
  50. int Tcp_retries = DEF_RETRIES;    /* Max retries before resetting tcb */
  51. int Tcp_trace;            /* State change tracing flag */
  52. int Tcp_syndata;
  53. struct tcp_rtt Tcp_rtt[RTTCACHE];
  54.  
  55. struct mib_entry Tcp_mib[] =
  56. {
  57.     {NULLCHAR,         {0}},
  58.     {"tcpRtoAlgorithm",     {4}},            /* Van Jacobsen's algorithm */
  59.     {"tcpRtoMin",         {0}},            /* No lower bound */
  60.     {"tcpRtoMax",         {MAXINT32}},        /* No upper bound */
  61.     {"tcpMaxConn",         {(uint32) - 1L}},    /* No limit */
  62.     {"tcpActiveOpens",     {0}},
  63.     {"tcpPassiveOpens",     {0}},
  64.     {"tcpAttemptFails",     {0}},
  65.     {"tcpEstabResets",     {0}},
  66.     {"tcpCurrEstab",     {0}},
  67.     {"tcpInSegs",         {0}},
  68.     {"tcpOutSegs",         {0}},
  69.     {"tcpRetransSegs",     {0}},
  70.     {NULLCHAR,         {0}},            /* Connection state goes here */
  71.     {"tcpInErrs",         {0}},
  72.     {"tcpOutRsts",         {0}}
  73. };
  74.  
  75.  
  76. /* Look up TCP connection
  77.  * Return TCB pointer or NULLTCB if nonexistant.
  78.  * Also move the entry to the top of the list to speed future searches.
  79.  */
  80. struct tcb *
  81. lookup_tcb (conn)
  82. register struct connection *conn;
  83. {
  84. register struct tcb *tcb;
  85. struct tcb *tcblast = NULLTCB;
  86.  
  87.     for (tcb = Tcbs; tcb != NULLTCB; tcblast = tcb, tcb = tcb->next) {
  88.         /* Yet another structure compatibility hack */
  89.         if (conn->remote.port == tcb->conn.remote.port
  90.             && conn->local.port == tcb->conn.local.port
  91.             && conn->remote.address == tcb->conn.remote.address
  92.             && conn->local.address == tcb->conn.local.address) {
  93.             if (tcblast != NULLTCB) {
  94.                 /* Move to top of list */
  95.                 tcblast->next = tcb->next;
  96.                 tcb->next = Tcbs;
  97.                 Tcbs = tcb;
  98.             }
  99.             return tcb;
  100.         }
  101.     }
  102.     return NULLTCB;
  103. }
  104.  
  105.  
  106. /* Create a TCB, return pointer. Return pointer if TCB already exists. */
  107. struct tcb *
  108. create_tcb (conn)
  109. struct connection *conn;
  110. {
  111. register struct tcb *tcb;
  112. struct tcp_rtt *tp;
  113.  
  114.     if ((tcb = lookup_tcb (conn)) != NULLTCB)
  115.         return tcb;
  116.     tcb = (struct tcb *) callocw (1, sizeof (struct tcb));
  117.  
  118.     ASSIGN (tcb->conn, *conn);
  119.  
  120.     tcb->state = TCP_CLOSED;
  121.     tcb->ssthresh = 65535U;
  122.     /* All this is now done in open_tcp() and tcp_in() - WG7J */
  123.     tcb->cwind = tcb->mss = Tcp_mss;
  124.     if ((tp = rtt_get (tcb->conn.remote.address)) != NULLRTT) {
  125.         tcb->srtt = tp->srtt;
  126.         tcb->mdev = tp->mdev;
  127.     } else
  128.         tcb->srtt = Tcp_irtt;    /* mdev = 0 */
  129.  
  130.     /* Initialize timer intervals */
  131.     set_timer (&tcb->timer, tcb->srtt);
  132.     tcb->timer.func = tcp_timeout;
  133.     tcb->timer.arg = tcb;
  134.  
  135.     /* point to the default interface parms block */
  136.     tcb->parms = &def_iftcp;
  137.  
  138.     tcb->next = Tcbs;
  139.     Tcbs = tcb;
  140.     return tcb;
  141. }
  142.  
  143. /* Close our TCB */
  144. void
  145. close_self (tcb, reason)
  146. register struct tcb *tcb;
  147. int reason;
  148. {
  149. struct reseq *rp1;
  150. register struct reseq *rp;
  151.  
  152.     if (tcb == NULLTCB)
  153.         return;
  154.  
  155.     stop_timer (&tcb->timer);
  156.     tcb->reason = (char) reason;
  157.  
  158.     /* Flush reassembly queue; nothing more can arrive */
  159.     for (rp = tcb->reseq; rp != NULLRESEQ; rp = rp1) {
  160.         rp1 = rp->next;
  161.         free_p (rp->bp);
  162.         free ((char *) rp);
  163.     }
  164.     tcb->reseq = NULLRESEQ;
  165.     setstate (tcb, TCP_CLOSED);
  166. }
  167.  
  168.  
  169. /* Sequence number comparisons
  170.  * Return true if x is between low and high inclusive,
  171.  * false otherwise
  172.  */
  173. int
  174. seq_within (x, low, high)
  175. register int32 x, low, high;
  176. {
  177.     if (low <= high) {
  178.         if (low <= x && x <= high)
  179.             return 1;
  180.     } else {
  181.         if (low >= x && x >= high)
  182.             return 1;
  183.     }
  184.     return 0;
  185. }
  186.  
  187.  
  188. int
  189. seq_lt (x, y)
  190. register int32 x, y;
  191. {
  192.     return (long) (x - y) < 0;
  193. }
  194.  
  195.  
  196. #if 0
  197. int
  198. seq_le (x, y)
  199. register int32 x, y;
  200. {
  201.     return (long) (x - y) <= 0;
  202. }
  203. #endif /* notdef */
  204.  
  205.  
  206. int
  207. seq_gt (x, y)
  208. register int32 x, y;
  209. {
  210.     return (long) (x - y) > 0;
  211. }
  212.  
  213.  
  214. int
  215. seq_ge (x, y)
  216. register int32 x, y;
  217. {
  218.     return (long) (x - y) >= 0;
  219. }
  220.  
  221.  
  222. void
  223. setstate (tcb, newstate)
  224. register struct tcb *tcb;
  225. register int newstate;
  226. {
  227. register char oldstate;
  228.  
  229.     oldstate = tcb->state;
  230.     tcb->state = (char) newstate;
  231.     if (Tcp_trace)
  232.         tcmdprintf ("TCB %lx %s -> %s\n", ptol (tcb),
  233.                 Tcpstates[(int) oldstate], Tcpstates[newstate]);
  234.  
  235.     /* Update MIB variables */
  236.     switch (oldstate) {
  237.         case TCP_CLOSED:
  238.             if (newstate == TCP_SYN_SENT)
  239.                 tcpActiveOpens++;
  240.             break;
  241.         case TCP_LISTEN:
  242.             if (newstate == TCP_SYN_RECEIVED)
  243.                 tcpPassiveOpens++;
  244.             break;
  245.         case TCP_SYN_SENT:
  246.             if (newstate == TCP_CLOSED)
  247.                 tcpAttemptFails++;
  248.             break;
  249.         case TCP_SYN_RECEIVED:
  250.             switch (newstate) {
  251.                 case TCP_CLOSED:
  252.                 case TCP_LISTEN:
  253.                     tcpAttemptFails++;
  254.                     break;
  255.                 default:
  256.                     break;
  257.             }
  258.             break;
  259.         case TCP_ESTABLISHED:
  260.         case TCP_CLOSE_WAIT:
  261.             switch (newstate) {
  262.                 case TCP_CLOSED:
  263.                 case TCP_LISTEN:
  264.                     tcpEstabResets++;
  265.                     break;
  266.                 default:
  267.                     break;
  268.             }
  269.             tcpCurrEstab--;
  270.             break;
  271.         default:
  272.             break;
  273.     }
  274.     if (newstate == TCP_ESTABLISHED || newstate == TCP_CLOSE_WAIT)
  275.         tcpCurrEstab++;
  276.  
  277.     if (tcb->s_upcall)
  278.         (*tcb->s_upcall) (tcb, oldstate, newstate);
  279.  
  280.     switch (newstate) {
  281.         case TCP_SYN_RECEIVED:
  282.         case TCP_ESTABLISHED:
  283.             /* Notify the user that he can begin sending data */
  284.             if (tcb->t_upcall)
  285.                 (*tcb->t_upcall) (tcb, tcb->window - tcb->sndcnt);
  286.             break;
  287.         default:
  288.             break;
  289.     }
  290. }
  291.  
  292.  
  293. /* Round trip timing cache routines.
  294.  * These functions implement a very simple system for keeping track of
  295.  * network performance for future use in new connections.
  296.  * The emphasis here is on speed of update (rather than optimum cache hit
  297.  * ratio) since rtt_add is called every time a TCP connection updates
  298.  * its round trip estimate.
  299.  */
  300. void
  301. rtt_add (addr, rtt)
  302. uint32 addr;            /* Destination IP address */
  303. int32 rtt;
  304. {
  305. register struct tcp_rtt *tp;
  306. int32 abserr;
  307.  
  308.     if (addr == 0)
  309.         return;
  310.     tp = &Tcp_rtt[(unsigned short) addr % RTTCACHE];
  311.     if (tp->addr != addr) {
  312.         /* New entry */
  313.         tp->addr = addr;
  314.         tp->srtt = rtt;
  315.         tp->mdev = 0;
  316.     } else {
  317.         /* Run our own SRTT and MDEV integrators, with rounding */
  318.         abserr = (rtt > tp->srtt) ? rtt - tp->srtt : tp->srtt - rtt;
  319.         /*lint -save -e704 */
  320.         tp->srtt = ((AGAIN - 1) * tp->srtt + rtt + (AGAIN / 2)) >> LAGAIN;
  321.         tp->mdev = ((DGAIN - 1) * tp->mdev + abserr + (DGAIN / 2)) >> LDGAIN;
  322.         /*lint -restore */
  323.     }
  324. }
  325.  
  326.  
  327. struct tcp_rtt *
  328. rtt_get (addr)
  329. uint32 addr;
  330. {
  331. register struct tcp_rtt *tp;
  332.  
  333.     if (addr == 0)
  334.         return NULLRTT;
  335.     tp = &Tcp_rtt[(unsigned short) addr % RTTCACHE];
  336.     if (tp->addr != addr)
  337.         return NULLRTT;
  338.     return tp;
  339. }
  340.  
  341.  
  342. #ifdef MSDOS
  343. /* TCP garbage collection - called by storage allocator when free space
  344.  * runs low. The send and receive queues are crunched. If the situation
  345.  * is red, the resequencing queue is discarded; otherwise it is
  346.  * also crunched.
  347.  */
  348. void
  349. tcp_garbage (red)
  350. int red;
  351. {
  352. register struct tcb *tcb;
  353. struct reseq *rp, *rp1;
  354.  
  355.     for (tcb = Tcbs; tcb != NULLTCB; tcb = tcb->next) {
  356.         mbuf_crunch (&tcb->rcvq);
  357.         mbuf_crunch (&tcb->sndq);
  358.         for (rp = tcb->reseq; rp != NULLRESEQ; rp = rp1) {
  359.             rp1 = rp->next;
  360.             if (red) {
  361.                 free_p (rp->bp);
  362.                 free ((char *) rp);
  363.             } else {
  364.                 mbuf_crunch (&rp->bp);
  365.             }
  366.         }
  367.         if (red)
  368.             tcb->reseq = NULLRESEQ;
  369.     }
  370. }
  371. #endif
  372.